using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace One_Crappy_RPG
{
    public class Creature
    {
        public delegate void OnHealthChangeHandler(EffectDamage.DamageType damageType, 
            Creature originator, int amount);
        public delegate void OnDeathHandler(Creature deceased);

        //Events
        public event OnHealthChangeHandler EventOnHealthChange;
        public event OnDeathHandler EventOnDeath;
        public event EventHandler EventOnTurnEnd;

        public struct CreatureInfo
        {
            public int Level;

            public int CurrentHealth;
            public int MaxHealth;

            public int CurrentMP;
            public int MaxMP;

            public int Strength;        //Determines physical damage done
            public int Intelligence;    //Determines magical damage done

            public int Speed;           //Determines turn order/hit rate
            public int Agility;         //Determines dodge rate

            public int Defense;         //Reduces physical damage
            public int MagicDefense;    //Reduces magic damage

            public int CurrentXP;       //On monsters:  How much XP to give
        }

        public Dictionary<EffectDamage.DamageType, int> Resists = new Dictionary<EffectDamage.DamageType, int>();
        public Dictionary<string, Spell> SpellBook = new Dictionary<string, Spell>();

        public CreatureInfo Stats;

        public List<BattleText> CombatText = new List<BattleText>();

        public Texture2D Texture;
        public Vector2 Position = Vector2.Zero;
        public Color drawColor = Color.White;
        
        public Random rng = new Random();

        public bool TurnInProgress = false;
        public float TurnTime;
        public float TurnLength;
        public bool MyTurn = false;
        public List<StatusEffect> TurnEffects = new List<StatusEffect>();

        float FlashDelay;
        Color FlashColor = Color.SlateGray;

        public string Name;

        public Creature()
        {
            EventOnHealthChange += OnHealthChange;
            EventOnDeath += OnDeath;
            EventOnTurnEnd += OnTurnEnd;
        }

        public virtual void HandleTurn(List<Creature> combatants)
        {
        }

        public virtual void Attack(Creature target)
        {
            int Damage;

            Damage = Stats.Strength * 2 - target.Stats.Defense;
            Damage = (int)(Damage * (rng.Next(90, 110) / 100.0f));

            Damage = (int)MathHelper.Clamp(Damage, 0, 999);

            TurnEffects.Add(new EffectDamage(EffectDamage.DamageType.Physical,
                Damage,
                target));

            TurnInProgress = true;
            TurnTime = 0.0f;
            TurnLength = 1.5f;
        }

        public virtual void CastSpell(Spell spell, Creature target)
        {
            SpellBook[spell.Name].Cast(target);
        }

        public virtual void Draw(SpriteBatch batch)
        {
              batch.Draw(Texture, Position, drawColor);
              foreach (BattleText text in CombatText)
                  text.Draw(batch);
        }

        public virtual void Update(GameTime gameTime)
        {            

            if (TurnInProgress)
            {
                TurnTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
                FlashDelay += (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (TurnTime >= TurnLength)
                {
                    TurnInProgress = false;
                    MyTurn = false;

                    //Actually apply the turn's effects now that our delay is up
                    FinishTurn();
                }

                //Flash between original and a new color 5 times during a turn
                //as a form of ghetto-animation
                if (FlashDelay >= (TurnLength / 5.0f))
                {
                    FlashDelay = 0.0f;
                    drawColor = Color.White;
                }
                else if (FlashDelay >= 0.5f * (TurnLength / 5.0f))
                {
                    drawColor = FlashColor;
                }
            }
            else
            {
                drawColor = Color.White;
            }

            for (int i = 0; i < CombatText.Count; i++)
            {
                if (CombatText[i].ElapsedTime < 0)
                {
                    CombatText.RemoveAt(i);
                    i--;
                    continue;
                }

                CombatText[i].Position.X = Position.X + (Texture.Width / 2);
                CombatText[i].Position.Y = Position.Y + Texture.Height;

                CombatText[i].Update(gameTime);

            }
        }

        public virtual void FinishTurn()
        {
            foreach (StatusEffect effect in TurnEffects)
                effect.ApplyEffect();

            TurnEffects.Clear();
        }

        public int ModifyDamage(EffectDamage.DamageType Type, int damage)
        {
            //If the creature has no resistance of that type, create it
            if (!Resists.ContainsKey(Type))
            {
                Resists.Add(Type, 0);
                return damage;
            }

            int resistance = Resists[Type];

            if (resistance == -1)
            {
                //Reverse the damage
                damage *= resistance;
            }
            else
            {
                damage *= (int)Math.Max((100 - resistance) / 100.0f, 0);
            }

            return damage;
        }


        public virtual void OnHealthChange(EffectDamage.DamageType type,
            Creature originator, int amount)
        {
            //Clamp HP
            Stats.CurrentHealth = (int)MathHelper.Clamp(Stats.CurrentHealth, 0, Stats.MaxHealth);


            if (Stats.CurrentHealth == 0 && EventOnDeath != null)
            {
                EventOnDeath(this);
            }

            CombatText.Add(new BattleText(amount, type));
        }

        public virtual void OnDeath(Creature deceased)
        {
        }

        public virtual void OnTurnEnd(object sender, EventArgs e)
        {
        }
    }
}
